package neuroPoker.poker;

import java.util.ArrayList;

import neuroPoker.poker.Enums.Actions;
import neuroPoker.poker.Enums.Stages;
import neuroPoker.visualisation.TablePan;

public class SimuSpiel extends Spiel {

	public PotSplitter potSplitter = new PotSplitter(this);

	public Dealer dealer;

	public SimuTisch tisch;

	// spieler der dran ist
	public int dran = 0;

	// aktuelle pos
	public int actPos;

	// aktueller pot
	protected int pot = 0;

	public SimuSpiel(SimuTisch tisch) {
		this.tisch = tisch;
		dealer = new Dealer(tisch);
	}

	/**
	 * @param partSpieler
	 *            Vector der teilnehmenden Spieler geordnet vom SB an im
	 *            uhrzeigersinn
	 **/
	public void execute(ArrayList<Spieler> partSpieler) {
		this.partSpieler = partSpieler;
		this.stillInSpieler = new ArrayList<Spieler>(partSpieler);
		if (partSpieler.size() < 2)
			return;
		// spiel spielen
		start();
		// gewinn auszahlen
		potSplitter.split();
	}

	protected void start() {
		// action-vektoren der spieler resetten / invested auf 0
		for (int i = 0; i < partSpieler.size(); i++) {
			partSpieler.get(i).preflopActions.clear();
			partSpieler.get(i).flopActions.clear();
			partSpieler.get(i).turnActions.clear();
			partSpieler.get(i).riverActions.clear();
			partSpieler.get(i).invested = 0;
		}
		einsatz = (einsatzAlt = (pot = 0));
		// karten austeilen
		dealer.deal(partSpieler);
		d = partSpieler.get(partSpieler.size() - 1);
		// blinds
		postBlinds();

		// einsatz ist 1 bb <=> 2sb
		einsatz = 2;

		// preFlop betRound starten
		stage = Stages.preFlop;
		betRound(2);
		if (stillInSpieler.size() < 2)
			return;

		// flop betRound starten
		einsatzAlt = einsatz;
		stage = Stages.flop;
		dealer.dealTableCards(3);
		betRound(0);
		if (stillInSpieler.size() < 2)
			return;

		// turn betRound starten
		einsatzAlt = einsatz;
		stage = Stages.turn;
		dealer.dealTableCards(1);
		betRound(0);
		if (stillInSpieler.size() < 2)
			return;

		// river betRound starten
		einsatzAlt = einsatz;
		stage = Stages.river;
		dealer.dealTableCards(1);
		betRound(0);
	}

	protected void postBlinds() {
		// sb
		sb = partSpieler.get(0);
		partSpieler.get(0).stack -= 1;
		partSpieler.get(0).invested += 1;
		pot += 1;
		// bb
		bb = partSpieler.get(1);
		partSpieler.get(1).stack -= 2;
		partSpieler.get(1).invested += 2;
		pot += 2;
	}

	protected void betRound(int aP) {
		this.actPos = aP;
		int raises = 0;
		int bfsize = stillInSpieler.size();
		for (int i = 0; stillInSpieler.size() > 1
				&& (i < bfsize || !evenInvested(stillInSpieler)); i++) {
			while (TablePan.paused)
				Util.sleep(500);
			dran = stillInSpieler.get(actPos).sitzPos;
			Actions action = stillInSpieler.get(actPos).getAction(
					raises < (stage == Stages.preFlop ? 3 : 4));
			// action des spielers speichern
			if (stage == Stages.preFlop)
				stillInSpieler.get(actPos).preflopActions.add(action);
			else if (stage == Stages.flop)
				stillInSpieler.get(actPos).flopActions.add(action);
			else if (stage == Stages.turn)
				stillInSpieler.get(actPos).turnActions.add(action);
			else if (stage == Stages.river)
				stillInSpieler.get(actPos).riverActions.add(action);

			if (action == Actions.raise)
				raises++;
			doAction(action);
			actPos = Util.next(stillInSpieler, actPos);
		}
	}

	protected void doAction(Actions action) {
		if (action == Actions.fold) {
			stillInSpieler.remove(actPos);
			actPos = --actPos % stillInSpieler.size();
		} else if (action == Actions.checkCall) {
			int kosten = einsatz - stillInSpieler.get(actPos).invested;
			stillInSpieler.get(actPos).invested += kosten;
			stillInSpieler.get(actPos).stack -= kosten;
			pot += kosten;
		} else if (action == Actions.raise) {
			int kosten = einsatz
					- stillInSpieler.get(actPos).invested
					+ ((stage == Stages.preFlop || stage == Stages.flop) ? 2
							: 4);
			stillInSpieler.get(actPos).invested += kosten;
			stillInSpieler.get(actPos).stack -= kosten;
			pot += kosten;
			einsatz = stillInSpieler.get(actPos).invested;
		}
	}

	protected boolean evenInvested(ArrayList<Spieler> spieler) {
		for (int i = 0; i < spieler.size(); i++) {
			if (spieler.get(i).invested != einsatz)
				return false;
		}
		return true;
	}

	@Override
	public int getPot() {
		return pot;
	}

	@Override
	public Spieler getBB() {
		return bb;
	}

	@Override
	public Spieler getD() {
		return d;
	}

	@Override
	public Spieler getSB() {
		return sb;
	}

	@Override
	public ArrayList<Spieler> getPartSpieler() {
		return partSpieler;
	}

	@Override
	public ArrayList<Spieler> getStillInSpieler() {
		return stillInSpieler;
	}

	@Override
	public int getEinsatz() {
		return einsatz;
	}

	@Override
	public int getEinsatzAlt() {
		return einsatzAlt;
	}

	@Override
	public Stages getStage() {
		return stage;
	}
}
